package com.hansen.library.utils;

import java.math.BigDecimal;

/**
 * 精确运算
 * 由于Java的简单类型不能够精确的对浮点数进行运算，这个工具类提供精 确的浮点数运算，包括加减乘除和四舍五入。
 * Created by han on 2017/8/7.
 */
public class ArithmeticUtil {
    // 默认除法运算精度
    private static final int DEFAULT_DIV_SCALE = 2;
    //---------------------------------------以下参数为String---------------------------------------

    /**
     * 提供精确的加法运算。
     *
     * @param str1 被加数
     * @param str2 加数
     * @return 两个参数的和
     */

    public static String add(String str1, String str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.add(b2).toString();
    }

    /**
     * 提供精确的加法运算。
     *
     * @param str1 被加数
     * @param str2 加数
     * @return 两个参数的和
     */

    public static String addAmount(String str1, String str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.add(b2).setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
    }

    /**
     * 提供精确的加法运算。
     *
     * @param str1 被加数
     * @param str2 加数
     * @return 两个参数的和
     */

    public static String add(String str1, int str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.add(b2).toString();
    }

    /**
     * 提供精确的加法运算。
     *
     * @param str1 被加数
     * @param str2 加数
     * @return 两个参数的和
     */

    public static int add(int str1, String str2) {
        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.add(b2).intValue();
    }

    /**
     * 提供精确的加法运算。
     *
     * @param str1 被加数
     * @param str2 加数
     * @return 两个参数的和
     */

    public static String addStr(int str1, String str2) {
        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.add(b2).toString();
    }


    /**
     * 提供精确的加法运算。
     *
     * @param str1 被加数
     * @param str2 加数
     * @return 两个参数的和
     */

    public static int add(int str1, int str2) {
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.add(b2).intValue();
    }

    /**
     * 提供精确的加法运算。
     *
     * @param str1 被加数
     * @param str2 加数
     * @return 两个参数的和
     */

    public static float add(float str1, float str2) {
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.add(b2).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param str1 被减数
     * @param str2 减数
     * @return 两个参数的差
     */

    public static String sub(String str1, String str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.subtract(b2).toString();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param str1 被减数
     * @param str2 减数
     * @return 两个参数的差
     */

    public static String sub(String str1, int str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.subtract(b2).toString();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param str1 被减数
     * @param str2 减数
     * @return 两个参数的差
     */

    public static float subsubFloat(String str1, String str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.subtract(b2).floatValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param str1 被减数
     * @param str2 减数
     * @return 两个参数的差
     */

    public static String subScaleAmount(String str1, String str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.subtract(b2).setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param str1 被减数
     * @param str2 减数
     * @return 两个参数的差
     */

    public static float sub(float str1, float str2) {

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.subtract(b2).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1 被乘数
     * @param i2   乘数
     * @return 两个参数的积
     */

    public static String mul(String str1, int i2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(Integer.toString(i2));

        return b1.multiply(b2).toString();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1 被乘数
     * @param i2   乘数
     * @return 两个参数的积
     */

    public static String mul(String str1, float i2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(i2);

        return b1.multiply(b2).toString();
    }



    /**
     * 提供精确的乘法运算。
     *
     * @param str1 被乘数
     * @param str2 乘数
     * @return 两个参数的积
     */
    public static String mul(String str1, String str2) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).toString();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static String mulScale2(int str1, float str2) {
        return mulScale(str1, str2, 2);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static String mulScale2(String str1, float str2) {
        return mulScale(str1, str2, 2);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static String mulScale2(String str1, String str2) {
        return mulScale(str1, str2, 2);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static int mulScale2(int str1, String str2) {
        return mulScale(str1, str2, 2);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static int mulScale2(int str1, int str2) {
        return mulScale(str1, str2, 2);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static String mulScale2(float str1, float str2) {
        return mulScale(str1, str2, 2);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @param scale 保留多少位
     * @return 两个参数的积
     */
    public static String mulScale(int str1, float str2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static float mulScaleFloat2(int str1, float str2) {

        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @param scale 保留多少位
     * @return 两个参数的积
     */
    public static int mulScale(int str1, int str2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).intValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @param scale 保留多少位
     * @return 两个参数的积
     */
    public static int mulScale(int str1, String str2, int scale) {
        if(!StringUtils.isNumber(str2)) {
            str2 = "0";
        }
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).intValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @param scale 保留多少位
     * @return 两个参数的积
     */
    public static String mulScale(String str1, float str2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @param scale 保留多少位
     * @return 两个参数的积
     */
    public static String mulScale(float str1, float str2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
    }


    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @param scale 保留多少位
     * @return 两个参数的积
     */
    public static String mulScale(String str1, String str2, int scale) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "0";
        }

        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param str1  被乘数
     * @param str2  乘数
     * @return 两个参数的积
     */
    public static String mulScaleAmount(String str1, String str2) {
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.multiply(b2).setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
    }

    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后2位，以后的数字四舍五入。
     *
     * @param str1 被除数
     * @param str1 除数
     * @return 两个参数的商
     */

    public static String div(String str1, String str2) {
        return div(str1, str2, DEFAULT_DIV_SCALE);
    }

    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后2位，以后的数字四舍五入。
     *
     * @param str1 被除数
     * @param str1 除数
     * @return 两个参数的商
     */

    public static float divFloat(String str1, String str2) {
        return divFloat(str1, str2, DEFAULT_DIV_SCALE);
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
     *
     * @param str1    被除数
     * @param str2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */

    public static String div(String str1, String str2, int scale) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "1";
        }

        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
     *
     * @param str1    被除数
     * @param str2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */

    public static float divFloat(String str1, String str2, int scale) {
        if (!StringUtils.isNumber(str1)) {
            str1 = "0";
        }

        if (!StringUtils.isNumber(str2)) {
            str2 = "1";
        }

        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
     *
     * @param str1    被除数
     * @param str2    除数
     * @return 两个参数的商
     */

    public static float divFloat2(float str1, float str2) {
        BigDecimal b1 = new BigDecimal(str1);
        BigDecimal b2 = new BigDecimal(str2);

        return b1.divide(b2, DEFAULT_DIV_SCALE, BigDecimal.ROUND_HALF_UP).floatValue();
    }
}
